/**
 * Created by Vivienfanghua on 2016/3/9.
 */

function calculator() {
    var object = new Object;
    var Pripority = {
        "+": {
            "+": 1,
            "-": 1,
            "*": -1,
            "/": -1,
            "(": -1,
            ")": 1,
            "#": 1
        }, "-": {
            "+": 1,
            "-": 1,
            "*": -1,
            "/": -1,
            "(": -1,
            ")": 1,
            "#": 1
        }, "*": {
            "+": 1,
            "-": 1,
            "*": 1,
            "/": 1,
            "(": -1,
            ")": 1,
            "#": 1
        }, "/": {
            "+": 1,
            "-": 1,
            "*": 1,
            "/": 1,
            "(": -1,
            ")": 1,
            "#": 1
        }, "(": {
            "+": -1,
            "-": -1,
            "*": -1,
            "/": -1,
            "(": -1,
            ")": 0,
            "#": null
        }, ")": {
            "+": 1,
            "-": 1,
            "*": 1,
            "/": 1,
            "(": null,
            ")": 1,
            "#": 1
        }, "#": {
            "+": -1,
            "-": -1,
            "*": -1,
            "/": -1,
            "(": -1,
            ")": null,
            "#": 0
        }
    }

    function getLast(stack) {
        return stack.length > 0 ? stack[stack.length - 1] : null;
    }

    function isOpt(s) {
        return "+-*/()".indexOf(s) != -1
    }

    function isNumber(string) {
        return isNaN(parseFloat(string)) ? false : true;
    }

    function arrayCac(Array1, Array2, Opt) {
        if (typeof(Array1) == "number" && typeof(Array2) == "object") {
            switch (Opt) {
                case "+":
                    return Array2.map(function (item) {
                        return Array1 + item;
                    });
                case "-":
                    return Array2.map(function (item) {
                        return Array1 - item;
                    });
                case "*":
                    return Array2.map(function (item) {
                        return Array1 * item;
                    });
                case "/":
                    return Array2.map(function (item) {
                        return Array1 / item;
                    });
            }
        }
        else if (typeof(Array2) == "number" && typeof(Array1) == "object") {
            switch (Opt) {
                case "+":
                    return Array1.map(function (item) {
                        return Array2 + item;
                    });
                case "-":
                    return Array1.map(function (item) {
                        return Array2 - item;
                    });
                case "*":
                    return Array1.map(function (item) {
                        return Array2 * item;
                    });
                case "/":
                    return Array1.map(function (item) {
                        return Array2 / item;
                    });
            }
        }
        else if (typeof(Array2) == "number" && typeof(Array1) == "number") {
            switch (Opt) {
                case "+":
                    return Array1+Array2;
                case "-":
                    return Array1-Array2;
                case "*":
                    return Array1*Array2;
                case "/":
                    return Array1/Array2;
            }
        }
        var output = [];
        switch (Opt) {
            case "+":
                for (var i in Array1)
                    output.push(Array1[i] + Array2[i]);
                break;
            case "-":
                for (var i in Array1)
                    output.push(Array1[i] - Array2[i]);
                break;
            case "*":
                for (var i in Array1)
                    output.push(Array1[i] * Array2[i]);
                break;
            case "/":
                for (var i in Array1)
                    output.push(1.0 * Array1[i] / Array2[i]);
                break;
        }
        return output;
    }

    object.parseExp = function (String) {
        var output = [];
        var item = "";

        for (var i = 0; i < String.length; i++) {
            if (isOpt(String[i])) {
                if (item != "")
                    output.push(item);
                output.push(String[i]);
                item = "";
            }
            else {
                item = item + String[i];
            }
        }
        if (item != "")
            output.push(item);
        return output;
    }
    object.Calc = function (MidExp1) {
        MidExp1.push("#");
        var MidExp = MidExp1.reverse();
        var stack = ['#'];
        var calStack = [];

        function getLast(stack) {
            return stack.length > 0 ? stack[stack.length - 1] : null;
        }

        var postFix = [];
        while (true) {
            var item = MidExp.pop();
            if (typeof(item) == "number") {
                postFix.push(item);
                continue;
            }
            while (true) {
                var stack_top = getLast(stack);
                if (Pripority[stack_top][item] == 1) {
                    postFix.push(stack.pop());
                    continue;
                }
                if (Pripority[stack_top][item] == -1) {
                    stack.push(item);
                    break;
                }
                if (Pripority[stack_top][item] == 0 && stack_top == "(" && item == ")") {
                    stack.pop();
                    break;
                }
                if (Pripority[stack_top][item] == 0 && stack_top == "#" && item == "#") {
                    break;
                }
            }
            if (item == "#" && getLast(stack) == "#")
                break;
        }
        for (var item in postFix) {
            if (typeof(postFix[item]) == "number")
                calStack.push(postFix[item]);
            else {
                switch (postFix[item]) {
                    case "+":
                        calStack.push(calStack.pop() + calStack.pop());
                        break;
                    case "-":
                        var first = calStack.pop();
                        var second = calStack.pop();
                        calStack.push(second - first);
                        break;
                    case "*":
                        calStack.push(calStack.pop() * calStack.pop());
                        break;
                    case "/":
                        var first = calStack.pop();
                        var second = calStack.pop();
                        calStack.push(second / first);
                        break;
                }
            }
        }
        return calStack.pop();
    }
    object.CalcArray = function (Data, Exp) {
        var MidExp1 = [];
        for (var i = 0; i < Exp.length; i++) {
            if (isOpt(Exp[i]))
                MidExp1.push(Exp[i]);
            else if (isNumber(Exp[i])) {
                MidExp1.push(parseFloat(Exp[i]));
            }
            else
                MidExp1.push(Data.get_attr_name(Exp[i]));
        }
        MidExp1.push("#");
        var MidExp = MidExp1.reverse();
        var stack = ['#'];
        var calStack = [];
        var postFix = [];
        while (true) {
            var item = MidExp.pop();
            if (typeof(item) == "object" || typeof(item) == "number") {
                postFix.push(item);
                continue;
            }
            while (true) {
                var stack_top = getLast(stack);
                if (Pripority[stack_top][item] == 1) {
                    postFix.push(stack.pop());
                    continue;
                }
                if (Pripority[stack_top][item] == -1) {
                    stack.push(item);
                    break;
                }
                if (Pripority[stack_top][item] == 0 && stack_top == "(" && item == ")") {
                    stack.pop();
                    break;
                }
                if (Pripority[stack_top][item] == 0 && stack_top == "#" && item == "#") {
                    break;
                }
            }
            if (item == "#" && getLast(stack) == "#")
                break;
        }
        //postFix=postFix.map(function(item){
        //    return isNumber(item)?parseFloat(item):item;
        //});
        for (var item in postFix) {
            if (typeof(postFix[item]) == "object" || typeof(postFix[item]) == "number")
                calStack.push(postFix[item]);
            else {
                switch (postFix[item]) {
                    case "+":
                        //TODO:数组计算
                        var first = calStack.pop();
                        var second = calStack.pop();
                        calStack.push(arrayCac(first, second, "+"));
                        break;
                    case "-":
                        var first = calStack.pop();
                        var second = calStack.pop();
                        calStack.push(arrayCac(second, first, "-"));
                        break;
                    case "*":
                        var first = calStack.pop();
                        var second = calStack.pop();
                        calStack.push(arrayCac(first, second, "*"));
                        break;
                    case "/":
                        var first = calStack.pop();
                        var second = calStack.pop();
                        calStack.push(arrayCac(second, first, "/"));
                        break;
                }
            }
        }
        return calStack.pop();
    }
    return object;
}

